
#include "xfat.h"
#include "xdisk.h"

u8_t temp_buffer[512];

/**
 * 初始化磁盘设备
 * @param disk 初始化的设备
 * @param name 设备的名称
 * @return
 */
xfat_err_t xdisk_open(xdisk_t *disk, const char * name, xdisk_driver_t * driver, void * init_data) {
    xfat_err_t err;

    disk->driver = driver;

    // 底层驱动初始化
    err = disk->driver->open(disk, init_data);
    if (err < 0) {
        return err;
    }

    disk->name = name;
    return FS_ERR_OK;
}

/**
 * 关闭存储设备
 * @param disk
 * @return
 */
xfat_err_t xdisk_close(xdisk_t * disk) {
    xfat_err_t err;

    err = disk->driver->close(disk);
    if (err < 0) {
        return err;
    }

    return err;
}

/**
 * 从设备中读取指定扇区数量的数据
 * @param disk 读取的磁盘
 * @param buffer 读取数据存储的缓冲区
 * @param start_sector 读取的起始扇区
 * @param count 读取的扇区数量
 * @return
 */
xfat_err_t xdisk_read_sector(xdisk_t *disk, u8_t *buffer, u32_t start_sector, u32_t count) {
    xfat_err_t err;

    if (start_sector + count >= disk->total_sector) {
        return FS_ERR_PARAM;
    }

    err = disk->driver->read_sector(disk, buffer, start_sector, count);
    return err;
}

/**
 * 向设备中写指定的扇区数量的数据
 * @param disk 写入的存储设备
 * @param buffer 数据源缓冲区
 * @param start_sector 写入的起始扇区
 * @param count 写入的扇区数
 * @return
 */
xfat_err_t xdisk_write_sector(xdisk_t *disk, u8_t *buffer, u32_t start_sector, u32_t count) {
    xfat_err_t err;

    if (start_sector + count >= disk->total_sector) {
        return FS_ERR_PARAM;
    }

    err = disk->driver->write_sector(disk, buffer, start_sector, count);
    return err;
}

/**
 * @brief 获取扩展分区下的子分区数量
 * 
 * @param disk 扩展分区所在的存储设备
 * @param start_sector 扩展分区所在的起始扇区
 * @param count 查询得到的子分区数量
 * @return xfat_err_t 
 */
static xfat_err_t disk_get_extend_part_count(xdisk_t * disk, u32_t start_sector, u32_t * count)
{
    int r_count = 0;
    u8_t *disk_buffer = temp_buffer;
    
    u32_t ext_start_sector = start_sector;
    do{
        mbr_part_t *part;

        //读取扩展分区的mbr
        int err = xdisk_read_sector(disk,disk_buffer,start_sector,1);
        if(err < 0)
        {
            return err;
        }

        //当前分区无效，立即退出
        part = ((mbr_t *)disk_buffer)->part_info;
        if(part->system_type == FS_NOT_VALID)
        {
            break;
        }

        r_count ++;

        //没有后续分区，立即退出
        if((++part)->system_type != FS_EXTEND)
        {
            break;
        }

        //寻找下一个分区
        start_sector = ext_start_sector + part->relative_sectors;
    }while (1);

    *count = r_count;
    return FS_ERR_OK;
}


/**
 * @brief 获取设备上总的分区数量
 * 
 * @param disk 查询的存储设备
 * @param count 分区数存储的位置
 * @return xfat_err_t 
 */
xfat_err_t xdisk_get_part_count(xdisk_t *disk,u32_t *count)
{
    int r_count = 0 , i = 0;
    mbr_part_t *part;
    u8_t *disk_buffer = temp_buffer;
    u8_t extend_part_flag = 0;
    u32_t start_sector[MBR_PRIMARY_PART_NR];    //原版此处直接写为4不妥

    //读取mbr区
    int err = xdisk_read_sector(disk,disk_buffer,0,1);
    if (err < 0)
    {
        return err;
    }

    //解析统计主分区的数量，标记出其中的扩展分区
    part = ((mbr_t *)disk_buffer)->part_info;
    for (i = 0;i< MBR_PRIMARY_PART_NR;i++,part++)
    {
        if (part->system_type == FS_NOT_VALID)
        {
            continue;
        }
        else if(part->system_type ==FS_EXTEND)
        {
            start_sector[i] = part->relative_sectors;
            extend_part_flag |= 1 << i;
        }
        else
        {
            r_count++;
        }
    }

    //统计各个扩展分区的子分区数目
    if(extend_part_flag)
    {
        for(i = 0;i < MBR_PRIMARY_PART_NR;i++)
        {
            if(extend_part_flag & (1 << i))
            {
                u32_t ext_count = 0;
                err = disk_get_extend_part_count(disk,start_sector[i],&ext_count);
                if(err < 0)
                {
                    return err;
                }
                r_count += ext_count;
            }
        }
    }
    
    *count = r_count;
    return FS_ERR_OK;
}

/**
 * @brief 获取扩展下分区信息
 * 
 * @param disk 查询的存储设备
 * @param disk_part 分区信息存储的位置
 * @param start_sector 扩展分区起始的绝对物理扇区
 * @param part_no 查询的分区号
 * @param count 该扩展分区下一共有多少个子分区
 * @return xfat_err_t 
 */
static xfat_err_t disk_get_extend_part(xdisk_t *disk,xdisk_part_t *disk_part,u32_t start_sector,int part_no,u32_t *count)
{
    int curr_no = -1;
    u8_t *disk_buffer = temp_buffer;
    xfat_err_t err = FS_ERR_OK;

    //遍历扩展分区
    u32_t ext_start_sector = start_sector;
    do{
        mbr_part_t *part;

        //读取扩展分区的mbr
        err = xdisk_read_sector(disk,disk_buffer,start_sector,1);
        if(err < 0)
        {
            return err;
        }

        part = ((mbr_t *)disk_buffer)->part_info;
        if(part->system_type == FS_NOT_VALID) //当前分区无效,设置未找到，返回
        {
            err = FS_ERR_EOF;
            break;
        }

        //找到指定的分区号，计算出分区的绝对位置信息
        if(++curr_no == part_no)
        {
            disk_part->type = part->system_type;
            disk_part->start_sector = start_sector + part->relative_sectors;
            disk_part->total_sector = part->total_sectors;
            disk_part->disk = disk;
            break;
        }

        if((++part)->system_type != FS_EXTEND) //无后续分区，设置未找到，返回
        {
            err = FS_ERR_EOF;
            break;
        }

        start_sector = ext_start_sector + part->relative_sectors;
    }while(1);

    *count = curr_no + 1;
    return err;
}

/**
 * @brief 获取指定的序号的分区信息
 * 该操作依赖物理分区分配，若设备分区结构有变化，序号则也会改变，得到的结果不同
 * @param disk 存储设备
 * @param xdisk_part 分区信息存储的位置
 * @param part_no 分区序号
 * @return xfat_err_t 
 */
xfat_err_t xdisk_get_part(xdisk_t *disk, xdisk_part_t *xdisk_part, int part_no)
{
    int i;
    int curr_no = -1;
    mbr_part_t * mbr_part;
	u8_t * disk_buffer = temp_buffer;

	// 读取mbr
	int err = xdisk_read_sector(disk, disk_buffer, 0, 1);
	if (err < 0) {
		return err;
	}

    //遍历4个主分区描述
    mbr_part = ((mbr_t *)disk_buffer)->part_info;
    for(i = 0;i < MBR_PRIMARY_PART_NR;i++,mbr_part++)
    {
        if(mbr_part->system_type == FS_NOT_VALID)
        {
            continue;
        }

        //如果扩展分区，则进入查询子分区
        if(mbr_part->system_type == FS_EXTEND)
        {
            u32_t count = 0;
            err = disk_get_extend_part(disk,xdisk_part,mbr_part->relative_sectors,part_no - i,&count);
            if(err < 0)
            {
                return err;
            }

            if(err == FS_ERR_OK)
            {
                return FS_ERR_OK;
            }
            else //未找到分区增加计数
            {
                curr_no += count;

                // todo: 扩展分区的查询破坏了当前读取缓冲，所以此处再次读取
                err = xdisk_read_sector(disk, disk_buffer, 0, 1);
                if (err < 0)
                {
                    return err;
                }
            }
        }
        else //在主分区找到，复制信息
        {
            if(++curr_no == part_no)
            {
                xdisk_part->type = mbr_part->system_type;
                xdisk_part->start_sector = mbr_part->relative_sectors;
                xdisk_part->total_sector = mbr_part->total_sectors;
                xdisk_part->disk = disk;
                return FS_ERR_OK;
            }
        }
    }
    return FS_ERR_NONE;
}



